﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Reflection;
using System.Linq;
using System.Xml;
using System.Xml.Linq;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.Configuration;
using Prologis.Logging;
using Prologis.ShifterNT.Extensions;
using System.Collections;


namespace Prologis.ShifterNT.Unity
{
    public static class Builder
    {
        static Logger log = new Logger(MethodBase.GetCurrentMethod().DeclaringType.Namespace);




        /// <summary>
        /// Gets the container.
        /// </summary>
        /// <param name="unityConfigpath">The unity configpath.</param>
        /// <returns></returns>
        public static IUnityContainer GetContainer(string unityConfigpath)
        {
            IUnityContainer container = new UnityContainer();
            UnityConfigurationSection section = GetUnityConfigurationSection(unityConfigpath);
            section.Containers.Default.Configure(container);
            return container;
        }


        /// <summary>
        /// Builds the shifter.
        /// </summary>
        /// <param name="unityConfigpath">The unity configpath.</param>
        /// <returns></returns>
        public static DefaultAppender BuildShifter(string unityConfigpath)
        {
            IUnityContainer container = GetContainer(unityConfigpath);
            return BuildShifter(container);
        }


        /// <summary>
        /// Tries the build shifter.
        /// </summary>
        /// <param name="unityConfigpath">The unity configpath.</param>
        /// <param name="defaultAppender">The default appender.</param>
        /// <returns></returns>
        public static bool TryBuildShifter(string unityConfigpath, DefaultAppender defaultAppender)
        {
            bool result = true;

            try
            {
                defaultAppender = BuildShifter(unityConfigpath);
            }
            catch (Exception e)
            {
                log.Exception(e, "TryBuildShifter failed! UnityConfigpath: " + unityConfigpath + ".");
                result = false;
            }

            return result;
        }



        /// <summary>
        /// Builds the shifter.
        /// </summary>
        /// <param name="container">The container.</param>
        /// <returns></returns>
        public static DefaultAppender BuildShifter(IUnityContainer container)
        {
            DefaultAppender defaultAppender = container.Resolve<DefaultAppender>();
            string fieldConfigPath = defaultAppender.DataSource.Tokenizer.FieldConfigPath;
            FieldList fieldList = GetFieldList(fieldConfigPath);
            defaultAppender.DataSource.Tokenizer.Fields = fieldList;
            log.Verbose("BuildShifter succeeded.");

            return defaultAppender;
        }


        public static FieldList GetFieldList(string fieldConfigPath)
        {
            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.Load(fieldConfigPath);
            XmlElement root = xmlDoc.DocumentElement;
            XmlElement fieldsElement = (XmlElement)root.SelectSingleNode("/fields");
            FieldList fieldList = ParseFieldsDefinition(fieldsElement);
            return fieldList;
        }

        

        /// <summary>
        /// Tries the build shifter.
        /// </summary>
        /// <param name="container">The container.</param>
        /// <param name="defaultAppender">The default appender.</param>
        /// <returns></returns>
        public static bool TryBuildShifter(IUnityContainer container, DefaultAppender defaultAppender)
        {
            bool result = true;

            try
            {
                defaultAppender = BuildShifter(container);
            }
            catch (Exception e)
            {
                log.Exception(e, "TryBuildShifter failed!");
                result = false;
            }

            return result;
        }



        /// <summary>
        /// Gets the unity configuration section.
        /// </summary>
        /// <param name="unityConfigpath">The unity configpath.</param>
        /// <returns></returns>
        public static UnityConfigurationSection GetUnityConfigurationSection(string unityConfigpath)
        {

            if (false == File.Exists(unityConfigpath))
            {
                throw new FileNotFoundException("Unity Builder can't find ConfigFile : " + unityConfigpath + " !");
            }

            ExeConfigurationFileMap map = new ExeConfigurationFileMap();
            map.ExeConfigFilename = unityConfigpath;

            System.Configuration.Configuration configuration = ConfigurationManager.OpenMappedExeConfiguration(map, ConfigurationUserLevel.None);
            UnityConfigurationSection section = (UnityConfigurationSection)configuration.GetSection("unity");

            if (section == null)
            {
                throw new Exception("Unity Builder can't load UnitySection from Config : " + unityConfigpath + " !");
            }
            return section;
        }




        /// <summary>
        /// Tries the get unity configuration section.
        /// </summary>
        /// <param name="unityConfigpath">The unity configpath.</param>
        /// <param name="unityConfigSection">The unity config section.</param>
        /// <returns></returns>
        public static bool TryGetUnityConfigurationSection(string unityConfigpath, UnityConfigurationSection unityConfigSection)
        {
            bool result = true;

            try
            {
                unityConfigSection = GetUnityConfigurationSection(unityConfigpath);
            }
            catch (Exception e)
            {
                log.Exception(e, "TryGetUnityConfigurationSection failed! UnityConfigpath: " + unityConfigpath);
                result = false;
            }

            return result;

        }




        //[0]	 {Index=0 Name=Field0   Value=null Source= Pos=0 Length=0 IsKey=False Enabled=True Default=}
        //[1]	 {Index=1 Name=Field1   Value=null Source= Pos=0 Length=0 IsKey=False Enabled=True Default=}
        //[2]	 {Index=2 Name=Field2   Value=null Source= Pos=0 Length=0 IsKey=False Enabled=True Default=}
        //[3]	 {Index=3 Name=Field3   Value=null Source= Pos=0 Length=0 IsKey=False Enabled=True Default=}
        //[4]	 {Index=4 Name=Field4   Value=null Source= Pos=0 Length=0 IsKey=False Enabled=True Default=}
        //[5]	 {Index=5 Name=Field5   Value=null Source= Pos=0 Length=0 IsKey=False Enabled=True Default=}
        //[6]	 {Index=6 Name=Field6   Value=null Source= Pos=0 Length=0 IsKey=False Enabled=True Default=}
        //[7]	 {Index=7 Name=Field7   Value=null Source= Pos=0 Length=0 IsKey=False Enabled=True Default=}
        //[8]	 {Index=8 Name=Field8   Value=null Source= Pos=0 Length=0 IsKey=False Enabled=True Default=}
        //[9]	 {Index=9 Name=Field9   Value=null Source= Pos=0 Length=0 IsKey=False Enabled=True Default=}
        //[10]   {Index=10 Name=Field10 Value=null Source= Pos=0 Length=0 IsKey=False Enabled=True Default=}
        //[11]   {Index=11 Name=Field11 Value=null Source= Pos=0 Length=0 IsKey=False Enabled=True Default=}


        /// <summary>
        /// Parses the fields static.
        /// </summary>
        /// <param name="fieldsElement">The fields element.</param>
        /// <returns></returns>
        public static FieldList ParseFieldsDefinition(XmlElement fieldsElement)
        {


            FieldList fields = new FieldList();

            if (fieldsElement.ChildNodes.Count == 0)
            {

                string countObject = fieldsElement.GetAttribute(FieldAttribute.count.ToString());
                string externalObject = fieldsElement.GetAttribute(FieldAttribute.external.ToString());
                
                if (externalObject == string.Empty && countObject != string.Empty)
                {
                    int fieldCount = int.Parse(countObject.ToString());
                    for (int i = 0; i < fieldCount; i++)
                    {
                        Field field = new Field("Field" + i);
                        //field.IsKey = false;
                        field.Source = fieldsElement.GetAttribute("source");
                        fields.Add(field);
                    }
                    fields.HasStrongNames = false;
                }
                else
                {
                    throw new Exception("Error in Fieldsdefinition!");
                }

            }

            for (int i = 0; i < fieldsElement.ChildNodes.Count; i++)
            {
                XmlNode node = fieldsElement.ChildNodes[i];
                if (node.NodeType == XmlNodeType.Element)
                {
                    Field field = GetFieldElement((XmlElement)node);
                    //if (field.Index == -1)
                    //{
                    //    field.Index = i;
                    //}
                    if (field.Source == String.Empty)
                    {
                        field.Source = "Main";
                    }
                    fields.Add(field);
                }
            }


            return fields;

        }


        /// <summary>
        /// Gets the field from element static.
        /// </summary>
        /// <param name="element">The element.</param>
        /// <returns></returns>
        public static Field GetFieldElement(XmlElement element)
        {

            Field field = new Field();

            foreach (XmlNode attribute in element.Attributes)
            {

                switch (attribute.Name.ToLower())
                {

                    case "name":
                        field.Name = attribute.Value;
                        break;

                    case "source":
                        field.Source = attribute.Value;
                        break;

                    case "pos":
                        field.Pos = int.Parse(attribute.Value);
                        break;

                    case "length":
                        field.Length = int.Parse(attribute.Value);
                        break;

                    //case "key":
                    //    field.IsKey = bool.Parse(attribute.Value);
                    //    break;

                    case "enabled":
                        field.Enabled = bool.Parse(attribute.Value);
                        break;

                    //case "index":
                    //    field.Index = int.Parse(attribute.Value);
                    //    break;

                    //case "isstring":
                    //    field.IsString = bool.Parse(attribute.Value);
                    //    break;

                    case "flexible":
                        field.Flexible = bool.Parse(attribute.Value);
                        break;


                    case "default":
                        field.Default = attribute.Value;
                        field.Value = field.Default;
                        break;

                }

            }

            return field;
        }

        


    }

}




